using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Threading;
using Microsoft.Surface;
using Microsoft.Surface.Presentation;
using Microsoft.Surface.Presentation.Controls;
using ESRI.ArcGIS.Client;
using ESRI.ArcGIS.Client.Geometry;
using ESRI.ArcGIS.Client.Tasks;

namespace ENMAX_ArcGIS
{
    /// <summary>
    /// Interaction logic for SurfaceWindow1.xaml
    /// Description: This is the Main Surface window. It includes a ScatterView and 
    /// 4 corner buttons containing the function menu ("Exit", "List", "Find").
    /// </summary>
    public partial class SurfaceWindow1 : SurfaceWindow
    {
        
        #region Animations of Looping Panels

        //private DoubleAnimation translateAnimation1, translateAnimation2, translateAnimation3, translateAnimation4;
        private DispatcherTimer UpperLeftTimer, UpperRightTimer, BtmLeftTimer, BtmRightTimer;
        //private bool list1Minimized, list2Minimized, list3Minimized, list4Minimized;
        private int ShrinkTime;
        
        private const int DragThreshold = 15;
        // List to store the input devices those do not need do the dragging check.
        private List<InputDevice> ignoredDeviceList = new List<InputDevice>();
        
        // Keep track of the current touch down contacts on the surface
        private Dictionary<int, MapPoint> touchPoints = new Dictionary<int,MapPoint>();

        private MapLayersMangerPanel layersPanel;
        #endregion

        /// <summary>
        /// Default constructor.
        /// </summary>
        public SurfaceWindow1()
        {
            
            InitializeComponent();

            // Add handlers for Application activation events
            AddActivationHandlers();

            //InitializeAnimation();

            InitializeTimer();

            //list1Minimized = true;
            //list2Minimized = true;
            //list3Minimized = true;
            //list4Minimized = true;

            /* Initialize the background map to Calgary location */
            BackgroundMap.Height = BackgroundMap.Height;
            BackgroundMap.Width = BackgroundMap.Width;
            BackgroundMap.Map.ExtentChanged += new EventHandler<ExtentEventArgs>(Map_ExtentChanged);

            BackgroundMap.Map.Layers = MapLayersManager.Instance.MapLayers;

            /* Setting the background of the surface to the
             * map of Calgary
             */
            BackgroundMap.setExtentFromEnvelop(new Envelope(-114.25, 51.00, -113.88, 51.05));
            BackgroundMap.AddVehiclePin(new VehiclePin(new MapPoint(-114.20, 51.002)));
            BackgroundMap.AddVehiclePin(new VehiclePin(new MapPoint(-113.90, 51.03)));
            BackgroundMap.AddVehiclePin(new VehiclePin(new MapPoint(-114.00, 51.035)));
            BackgroundMap.AddVehiclePin(new VehiclePin(new MapPoint(-114.01, 51.036)));
            BackgroundMap.AddVehiclePin(new VehiclePin(new MapPoint(-114.02, 51.04)));
            BackgroundMap.AddVehiclePin(new VehiclePin(new MapPoint(-114.03, 51.035)));
            BackgroundMap.AddVehiclePin(new VehiclePin(new MapPoint(-114.00, 51.01)));
            BackgroundMap.AddVehiclePin(new VehiclePin(new MapPoint(-114.00, 51.015)));
            BackgroundMap.AddVehiclePin(new VehiclePin(new MapPoint(-114.20, 51.01)));
            BackgroundMap.AddVehiclePin(new VehiclePin(new MapPoint(-113.90, 51.015)));
            BackgroundMap.AddVehiclePin(new VehiclePin(new MapPoint(-113.93, 51.035)));
            BackgroundMap.AddVehiclePin(new VehiclePin(new MapPoint(-113.95, 51.04)));
            

            /* Used by ghost frames to reference where to position the shadows */
            scatterLayer.RegisterBackgroundMap(BackgroundMap);
            layersPanel = new MapLayersMangerPanel();
            layersPanel.Center = new Point(500,500);
            layersPanel.Visibility = Visibility.Hidden;
            scatterLayer.Items.Add(layersPanel);
            /* used by the trouble pin layer to create map */
            troublePinLayer.MapScatterLayer = scatterLayer;
            
        }

        void Map_ExtentChanged(object sender, ExtentEventArgs e)
        {
            troublePinLayer.RemoveAllPins();
            ShowTroublePins();
        }

        # region Event Handlers

        /// <summary>
        /// Handles the event when the background map is loaded.
        /// When the background map is loaded, functions that
        /// rely on the final position of the background map relative
        /// to the screen can be called.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        protected void BackgroundMap_Loaded(object sender, EventArgs args)
        {
            /* trouble pins can only be loaded after the background
             * map has been loaded */
            //ShowTroublePins();
        }
        /// <summary>
        /// Occurs when the window is about to close. 
        /// </summary>
        /// <param name="e"></param>
        protected override void OnClosed(EventArgs e)
        {
            base.OnClosed(e);

            // Remove handlers for Application activation events
            RemoveActivationHandlers();
        }

        /// <summary>
        /// Adds handlers for Application activation events.
        /// </summary>
        private void AddActivationHandlers()
        {
            // Subscribe to surface application activation events
            ApplicationLauncher.ApplicationActivated += OnApplicationActivated;
            ApplicationLauncher.ApplicationPreviewed += OnApplicationPreviewed;
            ApplicationLauncher.ApplicationDeactivated += OnApplicationDeactivated;
            //this.Loaded += new RoutedEventHandler(BackgroundMap_Loaded);
        }

        /// <summary>
        /// Removes handlers for Application activation events.
        /// </summary>
        private void RemoveActivationHandlers()
        {
            // Unsubscribe from surface application activation events
            ApplicationLauncher.ApplicationActivated -= OnApplicationActivated;
            ApplicationLauncher.ApplicationPreviewed -= OnApplicationPreviewed;
            ApplicationLauncher.ApplicationDeactivated -= OnApplicationDeactivated;
            //this.Loaded -= new RoutedEventHandler(BackgroundMap_Loaded);
            //BackgroundMap.Loaded -= new RoutedEventHandler(BackgroundMap_Loaded);
        }

        /// <summary>
        /// This is called when application has been activated.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnApplicationActivated(object sender, EventArgs e)
        {
            //TODO: enable audio, animations here
            
        }

        /// <summary>
        /// This is called when application is in preview mode.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnApplicationPreviewed(object sender, EventArgs e)
        {
            //TODO: Disable audio here if it is enabled

            //TODO: optionally enable animations here
        }

        /// <summary>
        ///  This is called when application has been deactivated.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnApplicationDeactivated(object sender, EventArgs e)
        {
            //TODO: disable audio, animations here
        }


        /// <summary>
        ///  This is called when the close button is clicked
        /// </summary>
        private void CloseButtonBottomRight_Click(object sender, RoutedEventArgs e)
        {
            this.Close();
        }

        # endregion

        #region ListBox DND

        /// <summary>
        /// Handles the PreviewContactDown event for the ShoppingList.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnListPreviewContactDown(object sender, ContactEventArgs e)
        {
            ignoredDeviceList.Remove(e.Device);
            InputDeviceHelper.ClearDeviceState(e.Device);

            InputDeviceHelper.InitializeDeviceState(e.Device);
        }

        /// <summary>
        /// Handles the PreviewContactChanged event for the ShoppingList.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnListPreviewContactChanged(object sender, ContactEventArgs e)
        {
            SurfaceListBox senderListBox = sender as SurfaceListBox;

            // If this is a contact whose state has been initialized when its down event happens
            if (InputDeviceHelper.GetDragSource(e.Device) != null)
            {
                StartDragDrop(senderListBox, e);
            }
        }

        /// <summary>
        /// Handles the PreviewContactUp event for the ShoppingList.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnListPreviewContactUp(object sender, ContactEventArgs e)
        {
            ignoredDeviceList.Remove(e.Device);
            InputDeviceHelper.ClearDeviceState(e.Device);
        }

        /// <summary>
        /// When the drag is completed
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnListDragCompleted(object sender, SurfaceDragCompletedEventArgs e)
        {
            SurfaceListBox senderListBox = sender as SurfaceListBox;

            XmlElement draggingData = (XmlElement)e.Cursor.Data;

            SurfaceListBoxItem sourceListBoxItem = null;
            foreach (object item in senderListBox.Items)
            {
                if (((XmlElement)item).OuterXml == draggingData.OuterXml)
                {
                    sourceListBoxItem = senderListBox.ItemContainerGenerator.ContainerFromItem(item) as SurfaceListBoxItem;
                }
            }

            if (sourceListBoxItem != null)
            {
                sourceListBoxItem.Opacity = 1.0;
            }
        }

        /// <summary>
        /// Try to start Drag-and-drop for a listBox.
        /// </summary>
        /// <param name="sourceListBox"></param>
        /// <param name="e"></param>
        private void StartDragDrop(ListBox sourceListBox, InputEventArgs e)
        {
            // Check whether the input device is in the ignore list.
            if (ignoredDeviceList.Contains(e.Device))
            {
                return;
            }

            InputDeviceHelper.InitializeDeviceState(e.Device);

            Vector draggedDelta = InputDeviceHelper.DraggedDelta(e.Device, (UIElement)sourceListBox);

            // If this input device has moved more than Threshold pixels horizontally,
            // put it to the ignore list and never try to start drag-and-drop with it.
            if (Math.Abs(draggedDelta.X) > DragThreshold)
            {
                ignoredDeviceList.Add(e.Device);
                return;
            }

            // If this contact has moved less than Threshold pixels vertically 
            // then this is not a drag-and-drop yet.
            if (Math.Abs(draggedDelta.Y) < DragThreshold)
            {
                return;
            }

            ignoredDeviceList.Add(e.Device);

            // try to start drag-and-drop,
            // verify that the cursor the contact was placed at is a ListBoxItem
            DependencyObject downSource = InputDeviceHelper.GetDragSource(e.Device);
            //Debug.Assert(downSource != null);

            SurfaceListBoxItem draggedListBoxItem = GetVisualAncestor<SurfaceListBoxItem>(downSource);
            //Debug.Assert(draggedListBoxItem != null);

            // Get Xml source.
            XmlElement data = draggedListBoxItem.Content as XmlElement;

            // Data should be copied, because the Stack rejects data of the same instance.
            data = data.Clone() as XmlElement;

            // create a cursor to drag 
            ContentControl cursorVisual = new ContentControl();
            cursorVisual.Style = (Style)this.Resources["MyCursorStyle"];
            cursorVisual.DataContext = data;
            cursorVisual.Width = draggedListBoxItem.Width;
            cursorVisual.Height = 160;
                        
            IEnumerable<InputDevice> devices = null;

            ContactEventArgs contactEventArgs = e as ContactEventArgs;
            if (contactEventArgs != null)
            {
                devices = MergeContacts(draggedListBoxItem.ContactsCapturedWithin, contactEventArgs.Contact);
            }
            else
            {
                devices = new List<InputDevice>(new InputDevice[] { e.Device });
            }

            if (!SurfaceDragDrop.BeginDragDrop(sourceListBox, draggedListBoxItem, cursorVisual, data, devices, DragDropEffects.Copy))
            {
                return;
            }

            // Reset the input device's state.
            InputDeviceHelper.ClearDeviceState(e.Device);
            ignoredDeviceList.Remove(e.Device);

            draggedListBoxItem.Opacity = 0.5;
            e.Handled = true;
        }

        /// <summary>
        /// Attempts to get an ancestor of the passed-in element with the given type.
        /// </summary>
        /// <typeparam name="T">Type of ancestor to search for.</typeparam>
        /// <param name="descendent">Element whose ancestor to find.</param>
        /// <param name="ancestor">Returned ancestor or null if none found.</param>
        /// <returns>True if found, false otherwise.</returns>
        private static T GetVisualAncestor<T>(DependencyObject descendent) where T : class
        {
            T ancestor = null;
            DependencyObject scan = descendent;
            ancestor = null;

            while (scan != null && ((ancestor = scan as T) == null))
            {
                scan = VisualTreeHelper.GetParent(scan);
            }

            return ancestor;
        }

        /// <summary>
        /// Merges the remaining contacts on the drag source besides the contact that is down.
        /// </summary>
        /// <param name="existContacts"></param>
        /// <param name="extraContact"></param>
        /// <returns></returns>
        private static IEnumerable<InputDevice> MergeContacts(IEnumerable<Contact> existContacts, Contact extraContact)
        {
            var result = new List<InputDevice> { extraContact };

            foreach (Contact contact in existContacts)
            {
                if (contact != extraContact)
                {
                    result.Add(contact);
                }
            }

            return result;
        }


        #endregion

        #region Creating Detailed Map Windows (via 2-point touch)

        /// <summary>
        /// Keep track of which contact down the background map has
        /// received.  If there are 2 points current in the contact down
        /// state on the map, create a MapFrame with the map extent equal
        /// to the 2 finger touches relative to the background map.
        /// </summary>
        /// <param name="map"></param>
        /// <param name="args"></param>
        private void BackgroundMapContactDown(object map, ContactEventArgs args)
        {
            System.Windows.Point screenPoint = args.GetPosition(BackgroundMap);
            
            ESRI.ArcGIS.Client.Geometry.MapPoint mapPoint = (BackgroundMap).Map.ScreenToMap(screenPoint);

            touchPoints.Add(args.Contact.Id, mapPoint);

            if (touchPoints.Count == 2)
            {
                MapPoint mapPoint1 = touchPoints.ElementAt(0).Value;
                MapPoint mapPoint2 = touchPoints.ElementAt(1).Value;
                System.Windows.Point scrPoint1 = (BackgroundMap).Map.MapToScreen(mapPoint1);
                System.Windows.Point scrPoint2 = (BackgroundMap).Map.MapToScreen(mapPoint2);
                scatterLayer.CreateMapFrameFromMapPoints(mapPoint1, mapPoint2, scrPoint1, scrPoint2);
                touchPoints.Clear();
            }

        }

        /// <summary>
        /// If the finger leaves the background map, remove it
        /// from the list that keeps of all current contact down
        /// finger touches
        /// </summary>
        /// <param name="map"></param>
        /// <param name="args"></param>
        private void BackgroundMapContactUp(object map, ContactEventArgs args)
        {      
            if (touchPoints.ContainsKey(args.Contact.Id))
            {
                touchPoints.Remove(args.Contact.Id);
            }

        }

        #endregion

        #region Listbox animation (old, unused)
        /// <summary>
        /// Minimize the listbox.
        /// </summary>
        public void MinimizeListBox(SurfaceListBox list)
        {
            //if (list.Name.Equals("List1"))
            //{
            //    this.list1Minimized = true;
            //    this.translateAnimation1.From = this.trans.Y;
            //    this.translateAnimation1.To = 110;
            //    this.trans.BeginAnimation(TranslateTransform.YProperty, this.translateAnimation1);
            //}
            //if (list.Name.Equals("List2"))
            //{
            //    this.list2Minimized = true;
            //    this.translateAnimation2.From = this.trans2.Y;
            //    this.translateAnimation2.To = -110;
            //    this.trans2.BeginAnimation(TranslateTransform.YProperty, this.translateAnimation2);
            //}
            //if (list.Name.Equals("List3"))
            //{
            //    this.list3Minimized = true;
            //    this.translateAnimation3.From = this.trans3.X;
            //    this.translateAnimation3.To = -110;
            //    this.trans3.BeginAnimation(TranslateTransform.XProperty, this.translateAnimation3);
            //}
            //if (list.Name.Equals("List4"))
            //{
            //    this.list4Minimized = true;
            //    this.translateAnimation4.From = this.trans4.X;
            //    this.translateAnimation4.To = (755 + 110);
            //    this.trans4.BeginAnimation(TranslateTransform.XProperty, this.translateAnimation4);
            //}
        }

        /// <summary>
        /// Maximize the listbox.
        /// </summary>
        public void MaximizeListBox(SurfaceListBox list)
        {
            //if (list.Name.Equals("List1"))
            //{
            //    this.list1Minimized = false;
            //    this.translateAnimation1.From = this.trans.Y;
            //    this.translateAnimation1.To = 0;
            //    this.trans.BeginAnimation(TranslateTransform.YProperty, this.translateAnimation1);
            //}
            //if (list.Name.Equals("List2"))
            //{
            //    this.list2Minimized = false;
            //    this.translateAnimation2.From = this.trans2.Y;
            //    this.translateAnimation2.To = 0;
            //    this.trans2.BeginAnimation(TranslateTransform.YProperty, this.translateAnimation2);
            //}
            //if (list.Name.Equals("List3"))
            //{
            //    //because the menu has been rotated, so  we need change X
            //    this.list3Minimized = false;
            //    this.translateAnimation3.From = this.trans3.X;
            //    this.translateAnimation3.To = 0;
            //    this.trans3.BeginAnimation(TranslateTransform.XProperty, this.translateAnimation3);
            //}
            //if (list.Name.Equals("List4"))
            //{
            //    this.list4Minimized = false;
            //    this.translateAnimation4.From = this.trans4.X;
            //    this.translateAnimation4.To = 755;
            //    this.trans4.BeginAnimation(TranslateTransform.XProperty, this.translateAnimation4);
            //}
        }

        /// <summary>
        /// initialize the animation.
        /// </summary>
        private void InitializeAnimation()
        {

            //this.translateAnimation1 = new DoubleAnimation();
            //this.translateAnimation1.Duration = TimeSpan.FromSeconds(1);

            //this.translateAnimation2 = new DoubleAnimation();
            //this.translateAnimation2.Duration = TimeSpan.FromSeconds(1);

            //this.translateAnimation3 = new DoubleAnimation();
            //this.translateAnimation3.Duration = TimeSpan.FromSeconds(1);

            //this.translateAnimation4 = new DoubleAnimation();
            //this.translateAnimation4.Duration = TimeSpan.FromSeconds(1);



        }

        public void InitializeTimer()
        {

            this.ShrinkTime = 5;
            UpperLeftTimer = new System.Windows.Threading.DispatcherTimer();
            UpperLeftTimer.Tick += new EventHandler(dTimer_Tick);
            UpperLeftTimer.Interval = new TimeSpan(0, 0, ShrinkTime);

            UpperRightTimer = new System.Windows.Threading.DispatcherTimer();
            UpperRightTimer.Tick += new EventHandler(dTimer_Tick);
            UpperRightTimer.Interval = new TimeSpan(0, 0, ShrinkTime);

            BtmLeftTimer = new System.Windows.Threading.DispatcherTimer();
            BtmLeftTimer.Tick += new EventHandler(dTimer_Tick);
            BtmLeftTimer.Interval = new TimeSpan(0, 0, ShrinkTime);

            BtmRightTimer = new System.Windows.Threading.DispatcherTimer();
            BtmRightTimer.Tick += new EventHandler(dTimer_Tick);
            BtmRightTimer.Interval = new TimeSpan(0, 0, ShrinkTime);

        }

        private void dTimer_Tick(object sender, EventArgs args)
        {
            if (((DispatcherTimer)sender == UpperLeftTimer))
            {
                FunctionMenuUpperLeft.Visibility = Visibility.Hidden;
                ButtonUpperLeft.Visibility = Visibility.Visible;
            }

            if (((DispatcherTimer)sender == UpperRightTimer))
            {
                FunctionMenuUpperRight.Visibility = Visibility.Hidden;
                ButtonUpperRight.Visibility = Visibility.Visible;
            }

            if (((DispatcherTimer)sender == BtmLeftTimer))
            {
                FunctionMenuBottomLeft.Visibility = Visibility.Hidden;
                ButtonBottomLeft.Visibility = Visibility.Visible;
            }

            if (((DispatcherTimer)sender == BtmRightTimer))
            {
                FunctionMenuBottomRight.Visibility = Visibility.Hidden;
                ButtonBottomRight.Visibility = Visibility.Visible;
            }
        }

        #endregion

        #region Corner Button Animation

        /// <summary>
        /// This is called when a user clicks on the activated
        /// bottom right corner button.  When this occurs, the
        /// activated button retracts back to inactivated button.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void FunctionMenuBottomRight_Click(object sender, RoutedEventArgs e)
        {
            if (!ExitConfirmDialogBottomRight.IsVisible)
            {
                FunctionMenuBottomRight.Visibility = Visibility.Hidden;
                ButtonBottomRight.Visibility = Visibility.Visible;
                BtmRightTimer.Stop();
            }
        }

        /// <summary>
        /// This is called when a user clicks on the activated
        /// bottom left corner button.  When this occurs, the
        /// activated button retracts back to inactivated button.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void FunctionMenuBottomLeft_Click(object sender, RoutedEventArgs e)
        {
            if (!ExitConfirmDialogBottomLeft.IsVisible)
            {
                FunctionMenuBottomLeft.Visibility = Visibility.Hidden;
                ButtonBottomLeft.Visibility = Visibility.Visible;
                BtmLeftTimer.Stop();
            }
        }

        /// <summary>
        /// This is called when a user clicks on the activated
        /// upper right corner button.  When this occurs, the
        /// activated button retracts back to inactivated button.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void FunctionMenuUpperRight_Click(object sender, RoutedEventArgs e)
        {
            if (!ExitConfirmDialogUpperRight.IsVisible)
            {
                FunctionMenuUpperRight.Visibility = Visibility.Hidden;
                ButtonUpperRight.Visibility = Visibility.Visible;
                UpperRightTimer.Stop();
            }
        }

        /// <summary>
        /// This is called when a user clicks on the activated
        /// upper left corner button.  When this occurs, the
        /// activated button retracts back to inactivated button.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void FunctionMenuUpperLeft_Click(object sender, RoutedEventArgs e)
        {
            if (!ExitConfirmDialogUpperLeft.IsVisible)
            {
                FunctionMenuUpperLeft.Visibility = Visibility.Hidden;
                ButtonUpperLeft.Visibility = Visibility.Visible;
                UpperLeftTimer.Stop();
            }
        }

        /// <summary>
        /// This is called when a user clicks on the activated
        /// upper left corner button.  When this occurs, the
        /// activated button retracts back to inactivated button.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ButtonUpperLeft_Click(object sender, RoutedEventArgs e)
        {
            UpperLeftTimer.Start();

            ButtonUpperLeft.Visibility = Visibility.Hidden;
            FunctionMenuUpperLeft.Visibility = Visibility.Visible;
        }

        /// <summary>
        /// This is called when a user clicks on the inactivated
        /// upper right corner button.  This causes the FunctionMenu
        /// to appear making this button "activated".
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ButtonUpperRight_Click(object sender, RoutedEventArgs e)
        {
            UpperRightTimer.Start();

            ButtonUpperRight.Visibility = Visibility.Hidden;
            FunctionMenuUpperRight.Visibility = Visibility.Visible;
        }

        /// <summary>
        /// This is called when a user clicks on the inactivated
        /// bottom left corner button.  This causes the FunctionMenu
        /// to appear making this button "activated".
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ButtonBottomLeft_Click(object sender, RoutedEventArgs e)
        {
            BtmLeftTimer.Start();

            ButtonBottomLeft.Visibility = Visibility.Hidden;
            FunctionMenuBottomLeft.Visibility = Visibility.Visible;
        }

        /// <summary>
        /// This is called when a user clicks on the inactivated
        /// upper right corner button.  This causes the FunctionMenu
        /// to appear making this button "activated".
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ButtonBottomRight_Click(object sender, RoutedEventArgs e)
        {
            BtmRightTimer.Start();

            ButtonBottomRight.Visibility = Visibility.Hidden;
            FunctionMenuBottomRight.Visibility = Visibility.Visible;
        }

        #endregion

        #region FunctionMenu Buttons Handlers

        /// <summary>
        /// Handles the event when the Search button is clicked.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void SearchButton_Click(object sender, ContactEventArgs e)
        {
            //scatterLayer.AddSearchBox(new Point(500, 500));
            layersPanel.IsActive = true;
            layersPanel.Visibility = Visibility.Visible;
            
            layersPanel.Orientation = e.Contact.GetOrientation(this);
      
        }

        /// <summary>
        /// Closes the application when the user confirms
        /// to exit.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ConfirmExitButton_Click(object sender, RoutedEventArgs e)
        {
            this.Close();
        }

        /// <summary>
        /// The user cancels exit.  The exit confirmation dialog
        /// disappears and the related corner function menu button
        /// restarts the timer to hide.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void CancelExitButton_Click(object sender, RoutedEventArgs e)
        {
            SurfaceButton but = sender as SurfaceButton;
            ScatterViewItem exitWindow = but.TemplatedParent as ScatterViewItem;
            exitWindow.Visibility = Visibility.Hidden;

            switch (exitWindow.Name)
            {
                case "ExitConfirmDialogUpperLeft":
                    UpperLeftTimer.Start();
                    break;
                case "ExitConfirmDialogUpperRight":
                    UpperRightTimer.Start();
                    break;
                case "ExitConfirmDialogBottomLeft":
                    BtmLeftTimer.Start();
                    break;
                case "ExitConfirmDialogBottomRight":
                    BtmRightTimer.Start();
                    break;

            }
        }

        /// <summary>
        /// Handles the event when a user taps on the List button.
        /// This brings out a TroubleTicketListFrame with the same orientation
        /// of the touch finger.  The location of the list is close to the
        /// activating corner function menu.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ListButton_ContactTapGesture(object sender, ContactEventArgs e)
        {
            SurfaceButton but = sender as SurfaceButton;
            double ori = e.Contact.GetOrientation(this);
            SurfaceButton par = but.TemplatedParent as SurfaceButton;
            String buttonOrigin = par.Name;

            switch (buttonOrigin)
            {
                case "FunctionMenuUpperLeft":
                    scatterLayer.AddTroubleTicketListFrame(new Point(200, 850), ori);
                    break;
                case "FunctionMenuUpperRight":
                    scatterLayer.AddTroubleTicketListFrame(new Point(200, 200), ori);
                    break;
                case "FunctionMenuBottomLeft":
                    scatterLayer.AddTroubleTicketListFrame(new Point(550, 850), ori);
                    break;
                case "FunctionMenuBottomRight":
                    scatterLayer.AddTroubleTicketListFrame(new Point(550, 200), ori);
                    break;

            }
            e.Handled = true;
        }

        /// <summary>
        /// This is called when a user taps on the Exit
        /// button from the corner FunctionButton.
        /// It determines which FucntionMenu it came from
        /// and open the coresponding exit confirmation
        /// dialog.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ExitButton_ContactTapGesture(object sender, ContactEventArgs e)
        {
            SurfaceButton but = sender as SurfaceButton;
            SurfaceButton par = but.TemplatedParent as SurfaceButton;
            String buttonOrigin = par.Name;
            e.Handled = true;

            switch (buttonOrigin)
            {
                case "FunctionMenuUpperLeft":
                    UpperLeftTimer.Stop();
                    ExitConfirmDialogUpperLeft.RenderTransform = new RotateTransform(e.Contact.GetOrientation(this));                        
                    ExitConfirmDialogUpperLeft.Visibility = Visibility.Visible;
                    break;
                case "FunctionMenuUpperRight":
                    UpperRightTimer.Stop();
                    ExitConfirmDialogUpperRight.RenderTransform = new RotateTransform(e.Contact.GetOrientation(this));
                    ExitConfirmDialogUpperRight.Visibility = Visibility.Visible;
                    break;
                case "FunctionMenuBottomLeft":
                    BtmLeftTimer.Stop();
                    ExitConfirmDialogBottomLeft.RenderTransform = new RotateTransform(e.Contact.GetOrientation(this));
                    ExitConfirmDialogBottomLeft.Visibility = Visibility.Visible;
                    break;
                case "FunctionMenuBottomRight":
                    BtmRightTimer.Stop();
                    ExitConfirmDialogBottomRight.RenderTransform = new RotateTransform(e.Contact.GetOrientation(this));
                    ExitConfirmDialogBottomRight.Visibility = Visibility.Visible;
                    break;

            }
        }

        #endregion

        /// <summary>
        /// Used for demo purpose.  Populates the background map
        /// with TroubleTicketPins representing the location of 
        /// each TroubleTickets.
        /// </summary>
        public void ShowTroublePins()
        {

            /* create sample trouble tickets */
            Envelope mEnv1 = new Envelope(-114.165225251302,51.0199795790397,-114.149512923988,51.0355755135701);
            TroubleTicket tt1 = new TroubleTicket(mEnv1, "Out of order lights", "0006789", TroubleTicket.TroubleTicketSeverity.High);
            Point pt1 = (BackgroundMap).Map.MapToScreen(tt1.MapCoordinate);
            TroubleTicketPin ttpin1 = new TroubleTicketPin(tt1, new Point(Math.Abs(pt1.X-768), pt1.Y));
            ttpin1.MapTip = new ArcGisMapTip(scatterLayer, ttpin1);
            
            Envelope mEnv2 = new Envelope(-114.146822616181, 51.1247138317455, -114.12585847052, 51.1364297207226);
            TroubleTicket tt2 = new TroubleTicket(mEnv2, "Repair Transformer", "0006789", TroubleTicket.TroubleTicketSeverity.Medium);
            Point pt2 = (BackgroundMap).Map.MapToScreen(tt2.MapCoordinate);
            TroubleTicketPin ttpin2 = new TroubleTicketPin(tt2, new Point(Math.Abs(pt2.X - 768), pt2.Y));
            ttpin2.MapTip = new ArcGisMapTip(scatterLayer, ttpin2);

            Envelope mEnv3 = new Envelope(-114.05252218858, 51.1188308476309, -114.031558073198, 51.130546736608);
            TroubleTicket tt3 = new TroubleTicket(mEnv3, "Svc Request", "0006789", TroubleTicket.TroubleTicketSeverity.Low);
            Point pt3 = (BackgroundMap).Map.MapToScreen(tt3.MapCoordinate);
            TroubleTicketPin ttpin3 = new TroubleTicketPin(tt3, new Point(Math.Abs(pt3.X - 768), pt3.Y));
            ttpin3.MapTip = new ArcGisMapTip(scatterLayer, ttpin3);

            Envelope mEnv4 = new Envelope(-114.105225251302, 51.0199795790397, -114.109512923988, 51.0355755135701);
            TroubleTicket tt4 = new TroubleTicket(mEnv4, "Power outage", "0006789", TroubleTicket.TroubleTicketSeverity.High);
            Point pt4 = (BackgroundMap).Map.MapToScreen(tt4.MapCoordinate);
            TroubleTicketPin ttpin4 = new TroubleTicketPin(tt4, new Point(Math.Abs(pt4.X - 768), pt4.Y));
            ttpin4.MapTip = new ArcGisMapTip(scatterLayer, ttpin4);

            Envelope mEnv5 = new Envelope(-113.991064469202, 51.0490752572698, -113.970100323542, 51.0607911462469);
            TroubleTicket tt5 = new TroubleTicket(mEnv5, "New transformer Z12", "0006789", TroubleTicket.TroubleTicketSeverity.Medium);
            Point pt5 = (BackgroundMap).Map.MapToScreen(tt5.MapCoordinate);
            TroubleTicketPin ttpin5 = new TroubleTicketPin(tt5, new Point(Math.Abs(pt5.X - 768), pt5.Y));
            ttpin5.MapTip = new ArcGisMapTip(scatterLayer, ttpin5);

            Envelope mEnv6 = new Envelope(-114.099545255042, 51.0710092027607, -114.0785811092382, 51.0827250917378);
            TroubleTicket tt6 = new TroubleTicket(mEnv6, "Power outage", "0006789", TroubleTicket.TroubleTicketSeverity.Low);
            Point pt6 = (BackgroundMap).Map.MapToScreen(tt6.MapCoordinate);
            TroubleTicketPin ttpin6 = new TroubleTicketPin(tt6, new Point(Math.Abs(pt6.X - 768), pt6.Y));
            ttpin6.MapTip = new ArcGisMapTip(scatterLayer, ttpin6);

            Envelope mEnv7 = new Envelope(-114.080433237526, 50.913367183679, -114.059469091866, 50.92508307656);
            TroubleTicket tt7 = new TroubleTicket(mEnv7, "Wire installation", "0006789", TroubleTicket.TroubleTicketSeverity.High);
            Point pt7 = (BackgroundMap).Map.MapToScreen(tt7.MapCoordinate);
            TroubleTicketPin ttpin7 = new TroubleTicketPin(tt7, new Point(Math.Abs(pt7.X - 768), pt7.Y));
            ttpin7.MapTip = new ArcGisMapTip(scatterLayer, ttpin7);

            troublePinLayer.AddPinToLayer(ttpin1);
            troublePinLayer.AddPinToLayer(ttpin2);
            troublePinLayer.AddPinToLayer(ttpin3);
            troublePinLayer.AddPinToLayer(ttpin4);
            troublePinLayer.AddPinToLayer(ttpin5);
            troublePinLayer.AddPinToLayer(ttpin6);
            troublePinLayer.AddPinToLayer(ttpin7);
        }

        public void HideTroublePins()
        {
            //troublePinLayer.RemoveAllPins();
        }

    }
}